home *** CD-ROM | disk | FTP | other *** search
- #pragma implementation
- #include <string.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <linux/ip.h>
- #include <linux/tcp.h>
- #include <linux/udp.h>
- #include <linux/icmp.h>
- #include <linux/if.h>
- #include <linux/ip_fw.h>
- #include "netconf.h"
- #include "internal.h"
- #include "firewall.h"
- #include "../dialog/dialog.h"
- #include "../misc/misc.h"
- #include "../userconf/userconf.h"
- #include "../paths.h"
- #include "netconf.m"
-
- #ifndef IP_FW_POLICY_IN
- /* #Specification: firewall / compatibility
- linuxconf requires a kernel newer than 1.3.66 (or close) to
- support firewalling. Linuxconf works with older kernels but
- won't activate firewalling rules.
- */
- /* These are just here so it compiles */
- #define IP_FW_APPEND_IN 0
- #define IP_FW_APPEND_OUT 0
- #define IP_FW_APPEND_FWD 0
-
- #define IP_FW_POLICY_IN 0
- #define IP_FW_POLICY_OUT 0
- #define IP_FW_POLICY_FWD 0
-
- #define IP_FW_FLUSH_IN 0
- #define IP_FW_FLUSH_OUT 0
- #define IP_FW_FLUSH_FWD 0
-
- #define FIREWALL_NONE
- #endif
- extern NETCONF_HELP_FILE help_ipfw;
-
- static CONFIG_FILE ip_forward (PROC_NET_IP_FORWARD,help_ipfw
- ,CONFIGF_OPTIONNAL|CONFIGF_PROBED);
- static CONFIG_FILE ip_block (PROC_NET_IP_BLOCK,help_ipfw
- ,CONFIGF_OPTIONNAL|CONFIGF_PROBED);
- static CONFIG_FILE ip_input (PROC_NET_IP_INPUT,help_ipfw
- ,CONFIGF_OPTIONNAL|CONFIGF_PROBED);
- static CONFIG_FILE ip_output (PROC_NET_IP_OUTPUT,help_ipfw
- ,CONFIGF_OPTIONNAL|CONFIGF_PROBED);
- static CONFIG_FILE ip_acct (PROC_NET_IP_ACCT,help_ipfw
- ,CONFIGF_OPTIONNAL|CONFIGF_PROBED);
-
- static CONFIG_FILE f_current_acct (VAR_RUN_FIREWALL_ACCT,help_ipfw
- ,CONFIGF_GENERATED|CONFIGF_OPTIONNAL|CONFIGF_ERASED);
- static CONFIG_FILE f_current_block (VAR_RUN_FIREWALL_BLOCK,help_ipfw
- ,CONFIGF_GENERATED|CONFIGF_OPTIONNAL|CONFIGF_ERASED);
- static CONFIG_FILE f_current_forwd (VAR_RUN_FIREWALL_FORWD,help_ipfw
- ,CONFIGF_GENERATED|CONFIGF_OPTIONNAL|CONFIGF_ERASED);
- static CONFIG_FILE f_current_output (VAR_RUN_FIREWALL_OUTPUT,help_ipfw
- ,CONFIGF_GENERATED|CONFIGF_OPTIONNAL|CONFIGF_ERASED);
-
-
-
- class IPFW_RULES: public ARRAY{
- public:
- char active;
- private:
- virtual IPFW_RULE *newrule()=0;
- virtual IPFW_RULE *newrule(const char *pt)=0;
- virtual int save()=0;
- virtual int kernelok()=0;
- virtual int enable(int doit, SSTRING *collect)=0;
- public:
- virtual int disable(int doit, SSTRING *collect)=0;
- /*~PROTOBEG~ IPFW_RULES */
- public:
- void edit (void);
- IPFW_RULE *getitem (int no);
- protected:
- void init (const char *key,
- const char *key_active);
- private:
- void reset_nbbitmsk (void);
- protected:
- int savek (const char *key,
- const char *key_active);
- public:
- int setup (int doit, SSTRING *collect);
- /*~PROTOEND~ IPFW_RULES */
- };
- class IPFW_RULES_FORWARD: public IPFW_RULES{
- /*~PROTOBEG~ IPFW_RULES_FORWARD */
- public:
- IPFW_RULES_FORWARD (void);
- int disable (int doit, SSTRING *collect);
- int enable (int doit, SSTRING *collect);
- int kernelok (void);
- protected:
- IPFW_RULE *newrule (const char *pt);
- IPFW_RULE *newrule (void);
- public:
- int save (void);
- /*~PROTOEND~ IPFW_RULES_FORWARD */
- };
- class IPFW_RULES_INPUT: public IPFW_RULES{
- /*~PROTOBEG~ IPFW_RULES_INPUT */
- public:
- IPFW_RULES_INPUT (void);
- int disable (int doit, SSTRING *collect);
- int enable (int doit, SSTRING *collect);
- int kernelok (void);
- protected:
- IPFW_RULE *newrule (const char *pt);
- IPFW_RULE *newrule (void);
- public:
- int save (void);
- /*~PROTOEND~ IPFW_RULES_INPUT */
- };
- class IPFW_RULES_OUTPUT: public IPFW_RULES{
- /*~PROTOBEG~ IPFW_RULES_OUTPUT */
- public:
- IPFW_RULES_OUTPUT (void);
- int disable (int doit, SSTRING *collect);
- int enable (int doit, SSTRING *collect);
- int kernelok (void);
- protected:
- IPFW_RULE *newrule (const char *pt);
- IPFW_RULE *newrule (void);
- public:
- int save (void);
- /*~PROTOEND~ IPFW_RULES_OUTPUT */
- };
-
- PUBLIC IPFW_RULE *IPFW_RULES::getitem(int no)
- {
- return (IPFW_RULE*)ARRAY::getitem(no);
- }
-
- static char ACTIVEF[] = "activef";
- static char ACTIVEB[] = "activeb";
- static char ACTIVEO[] = "activeo";
- //static char ACTIVEA[] = "activea";
-
- PROTECTED void IPFW_RULES::init (const char *key, const char *key_active)
- {
- SSTRINGS strs;
- active = linuxconf_getvalnum (FIREWALL,key_active,0);
- linuxconf_getall (FIREWALL,key,strs,0);
- int nb = strs.getnb();
- for (int i=0; i<nb; i++){
- SSTRING *s = strs.getitem(i);
- add (newrule (s->get()));
- }
- rstmodified();
- }
-
- PUBLIC IPFW_RULES_FORWARD::IPFW_RULES_FORWARD()
- {
- init (FORWARD,ACTIVEF);
- }
-
- PUBLIC IPFW_RULES_INPUT::IPFW_RULES_INPUT()
- {
- init (BLOCK,ACTIVEB);
- }
- PUBLIC IPFW_RULES_OUTPUT::IPFW_RULES_OUTPUT()
- {
- init (OUTPUT,ACTIVEO);
- }
-
-
- PROTECTED int IPFW_RULES::savek(const char *key, const char *key_active)
- {
- int ret = -1;
- if (perm_rootaccess("update firewalling configuration")){
- int nb = getnb();
- linuxconf_replace (FIREWALL,key_active,active);
- linuxconf_removeall(FIREWALL,key);
- for (int i=0; i<nb; i++){
- getitem(i)->save();
- }
- ret = linuxconf_save();
- }
- return ret;
- }
-
-
- PUBLIC int IPFW_RULES_FORWARD::save()
- {
- return IPFW_RULES::savek (FORWARD,ACTIVEF);
- }
-
- PROTECTED IPFW_RULE *IPFW_RULES_FORWARD::newrule()
- {
- return new IPFW_RULE_FORWARD;
- }
- PROTECTED IPFW_RULE *IPFW_RULES_FORWARD::newrule(const char *pt)
- {
- return new IPFW_RULE_FORWARD (pt);
- }
-
- PUBLIC int IPFW_RULES_INPUT::save()
- {
- return IPFW_RULES::savek (BLOCK,ACTIVEB);
- }
- PROTECTED IPFW_RULE *IPFW_RULES_INPUT::newrule()
- {
- return new IPFW_RULE_INPUT;
- }
- PROTECTED IPFW_RULE *IPFW_RULES_INPUT::newrule(const char *pt)
- {
- return new IPFW_RULE_INPUT (pt);
- }
-
- PUBLIC int IPFW_RULES_OUTPUT::save()
- {
- return IPFW_RULES::savek (OUTPUT,ACTIVEO);
- }
- PROTECTED IPFW_RULE *IPFW_RULES_OUTPUT::newrule()
- {
- return new IPFW_RULE_OUTPUT;
- }
- PROTECTED IPFW_RULE *IPFW_RULES_OUTPUT::newrule(const char *pt)
- {
- return new IPFW_RULE_OUTPUT (pt);
- }
-
- /*
- Edit all firewalling rules
- */
- PUBLIC void IPFW_RULES::edit()
- {
- if (perm_rootaccess("edit firewalling rules")){
- int choice = 0;
- while (1){
- int nb = getnb();
- const char **menuopt
- = (const char**)malloc(((nb*2)+1)*sizeof(char*));
- int i;
- int ii=0;
- for (i=0; i<nb; i++){
- menuopt[ii++] = " ";
- char buf[100];
- getitem(i)->present (buf);
- menuopt[ii++] = strdup(buf);
- }
- menuopt[ii] = NULL;
- MENU_STATUS code = xconf_menu(
- MSG_U(T_EDITFIRE,"Edit firewalling rules")
- ,MSG_U(I_EDITFIRE
- ,"You are allowed to edit/add/deleted\n"
- "rules for forwarding packets")
- ,help_ipfw
- ,NULL
- ,NULL
- ,NULL
- ,MSG_U(I_NEWRULES,"new rules")
- ,menuopt
- ,choice);
- IPFW_RULE *item = NULL;
- if (choice >=0 && choice < nb){
- item = getitem(choice);
- }
- for (i=0; i<nb; i++) free ((char*)(menuopt[i*2+1]));
- free ((char**)menuopt);
- if (code == MENU_ESCAPE || code == MENU_QUIT){
- break;
- }else if (perm_rootaccess("modify firewalling rules")){
- if (code == MENU_OK){
- if (item != NULL){
- int ok = item->edit();
- if (ok >= 0){
- if (ok == 1) remove_del(item);
- save();
- }
- }
- }else if (code == MENU_ADD){
- IPFW_RULE *a = newrule();
- if (a->edit() == 0){
- add (a);
- save();
- }else{
- delete a;
- }
- }
- }
- }
- }
- }
-
- /*
- Turn off completly blocking
- */
- PUBLIC int IPFW_RULES_INPUT::disable(
- int doit,
- SSTRING *collect)
- {
- // The order is important as the reverse will break connectivity
- // for a moment.
- return ipfw_policy (doit,collect,IP_FW_POLICY_IN,IP_FW_F_ACCEPT) == -1
- || ipfw_flush(doit,collect,IP_FW_FLUSH_IN) == -1
- ? -1 : 0;
- }
- /*
- Turn on blocking
- */
- PUBLIC int IPFW_RULES_INPUT::enable(
- int doit,
- SSTRING *collect)
- {
- struct ip_fw bf;
- ipfw_baseinit ("127.0.0.1","all"
- ,"127.0.0.1","255.255.255.255","",""
- ,"127.0.0.1","255.255.255.255","",""
- ,bf);
- return ipfw_append (doit,collect,IP_FW_APPEND_IN,bf) == -1
- || ipfw_policy (doit,collect,IP_FW_POLICY_IN,0) == -1
- ? -1 : 0;
- }
- /*
- check if the kernel do support blocking
- */
- PUBLIC int IPFW_RULES_INPUT::kernelok()
- {
- int ret = 1;
- if (!ip_block.exist() && !ip_input.exist()){
- static char shutoff = 0;
- if (!shutoff){
- xconf_error (MSG_U(ERR_BLOCKING
- ,"The kernel does not support\n"
- "IP_BLOCKING, reconfigure it"));
- shutoff = 1;
- }
- ret = 0;
- }
- return ret;
- }
- /*
- Turn off completly forwarding
- */
- PUBLIC int IPFW_RULES_OUTPUT::disable(
- int doit,
- SSTRING *collect)
- {
- return ipfw_policy (doit,collect,IP_FW_POLICY_OUT,IP_FW_F_ACCEPT) == -1
- || ipfw_flush(doit,collect,IP_FW_FLUSH_OUT) == -1
- ? -1 : 0;
- }
- /*
- Turn on forwarding firewall
- */
- PUBLIC int IPFW_RULES_OUTPUT::enable(
- int doit,
- SSTRING *collect)
- {
- /* #Specification: firewall / strategy
- The blocking and outputing mecanism use a positive
- logic. Everything is deny at first. Each rule supplied
- by the user is opening a new hole.
-
- The firewalling code of Linux is more general than that.
- It should be good enough for most firewall and simple
- for users/admin too.
- */
- struct ip_fw bf;
- ipfw_baseinit ("127.0.0.1","all"
- ,"127.0.0.1","255.255.255.255","",""
- ,"127.0.0.1","255.255.255.255","",""
- ,bf);
- return ipfw_append (doit,collect,IP_FW_APPEND_OUT,bf) == -1
- || ipfw_policy (doit,collect,IP_FW_POLICY_OUT,0) == -1
- ? -1 : 0;
- }
- /*
- Turn off completly forwarding
- */
- PUBLIC int IPFW_RULES_FORWARD::disable(
- int doit,
- SSTRING *collect)
- {
- return ipfw_policy (doit,collect,IP_FW_POLICY_FWD,IP_FW_F_ACCEPT) == -1
- || ipfw_flush(doit,collect,IP_FW_FLUSH_FWD) == -1
- ? -1 : 0;
- }
- /*
- Turn on forwarding firewall
- */
- PUBLIC int IPFW_RULES_FORWARD::enable(
- int doit,
- SSTRING *collect)
- {
- return ipfw_policy (doit,collect,IP_FW_POLICY_FWD,0) == -1
- ? -1 : 0;
- }
- /*
- check if the kernel do support forwarding
- */
- PUBLIC int IPFW_RULES_FORWARD::kernelok()
- {
- int ret = 1;
- if (!ip_forward.exist()){
- static char shutoff = 0;
- if (!shutoff){
- xconf_error (MSG_U(ERR_FORWARDING
- ,"The kernel does not support\n"
- "IP_FORWARDING, reconfigure it"));
- shutoff = 1;
- }
- ret = 0;
- }
- return ret;
- }
- /*
- check if the kernel do support outputint
- */
- PUBLIC int IPFW_RULES_OUTPUT::kernelok()
- {
- int ret = 1;
- if (!ip_output.exist()){
- static char shutoff = 0;
- if (!shutoff){
- xconf_error (MSG_U(ERR_OUTPUT
- ,"The kernel does not support\n"
- "IP_OUTPUTING, reconfigure it"));
- shutoff = 1;
- }
- ret = 0;
- }
- return ret;
- }
-
- /*
- Compare by netmask. host netmask will be first, 0.0.0.0 will be last
- */
- static int cmp_by_netmask_from (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
- {
- IPFW_RULE *r1 = (IPFW_RULE*)o1;
- IPFW_RULE *r2 = (IPFW_RULE*)o2;
- return r2->nbbitmask_from() - r1->nbbitmask_from();
- }
- /*
- Compare by netmask. host netmask will be first, 0.0.0.0 will be last
- */
- static int cmp_by_netmask_to (const ARRAY_OBJ *o1, const ARRAY_OBJ *o2)
- {
- IPFW_RULE *r1 = (IPFW_RULE*)o1;
- IPFW_RULE *r2 = (IPFW_RULE*)o2;
- return r2->nbbitmask_to() - r1->nbbitmask_to();
- }
-
- PRIVATE void IPFW_RULES::reset_nbbitmsk()
- {
- int n = getnb();
- for (int i=0; i<n; i++){
- IPFW_RULE *r = getitem(i);
- r->from.nbbit_msk = -1;
- r->to.nbbit_msk = -1;
- }
- }
-
- /*
- Apply the firewalling rules
- */
- PUBLIC int IPFW_RULES::setup(
- int doit,
- SSTRING *collect)
- {
- int ret = 0;
- /* #Specification: netconf / firewalling / logic
- The firewalling strategy is this. When activating
- one rule set (blocking, forwarding), you are closing
- the door (policy deny). Each rule you enter open
- a door. This is less general than using ipfw directly
- but much simpler and enough for most usage.
-
- Comments are more than welcome about this.
-
- While setting the rules, we set the policy to accept.
- We set it to deny at the end of the rule sequence. This
- prevent some interruption in the networking while
- installing the rules. If we would have start by denying
- everything, we could have add all kind of network timeout
- while trying to set the rules. Quite often, setting rules
- involve DNS access.
- */
- if (active){
- if (!kernelok()
- || disable(doit,collect)==-1){
- ret = -1;
- }else{
- ret = 0;
- reset_nbbitmsk();
- sort (cmp_by_netmask_from);
- int nbr = getnb();
- int i;
- for (i=0; i<nbr; i++){
- IPFW_RULE *r = getitem(i);
- ret |= r->setup_left(doit,collect);
- }
- sort (cmp_by_netmask_to);
- for (i=0; i<nbr; i++){
- IPFW_RULE *r = getitem(i);
- ret |= r->setup_right(doit,collect);
- }
- ret = enable (doit,collect);
- }
- }
- return ret;
- }
- #ifndef FIREWALL_NONE
-
- static int firewall_setup (
- IPFW_RULES &rules,
- CONFIG_FILE &f_current)
- {
- int ret = 0;
- SSTRING collect;
- if (rules.setup(0,&collect) != -1){
- SSTRING current;
- /* #Specification: firewalling / update needed
- Probing the firewalling information to find
- out if the current configuration is already
- configured in the kernel is not easy. A trick
- is used here. All the command generated to
- configured the kernel are saved in the files
- /var/run/firewall.{acct,block,forwd}.
-
- When probing the firewall setup, we generate
- the command in a string and compare that string
- with the content of the file. If there is
- any mismatch, the complete firewalling sequence
- is reprogrammend in the kernel and the string
- is saved in /var/run/firewall.state.
- */
- FILE *fin = f_current.fopen ("r");
- if (fin != NULL){
- char buf[1000];
- while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
- current.append (buf);
- }
- fclose (fin);
- }
- if (current.cmp(collect)!=0){
- if(collect.is_empty()){
- // No rules needed but the firewall must be desactivated
- rules.disable(0,&collect);
- if (!simul_ison()){
- f_current.unlink();
- rules.disable(1,NULL);
- }
- }else{
- if (!simul_ison()){
- ret = rules.setup(1,NULL);
- if (ret != -1){
- FILE *fout = f_current.fopen ("w");
- if (fout != NULL){
- fputs (collect.get(),fout);
- fclose (fout);
- }
- }
- }
- }
- net_prtlog ("%s",collect.get());
- }
- }
- return ret;
- }
- #endif
- /*
- Install the firewalling rules in the kernel.
- Return -1 if any errors
- */
- int firewall_setup()
- {
- int ret = -1;
- IPFW_RULES_FORWARD frules;
- IPFW_RULES_INPUT brules;
- IPFW_RULES_OUTPUT orules;
- if (frules.active || brules.active || orules.active){
- #ifdef FIREWALL_NONE
- xconf_error (MSG_U(E_FWOLDKERN
- ,"Linuxconf was compiled on an old kernel and does not\n"
- "support firewalling properly. No rule will be activated."));
- #else
- if (perm_rootaccess("activating the firewalling configuration")){
- if (ipfw_open() != -1
- && firewall_setup (frules,f_current_forwd) != -1
- && firewall_setup (brules,f_current_block) != -1
- && firewall_setup (orules,f_current_output) != -1){
- ipfw_close();
- ret = 0;
- }
- }
- #endif
- }
- return ret;
- }
- /*
- Reset the firewalling rules in the kernel.
- Return -1 if any errors
- */
- int firewall_reset()
- {
- int ret = -1;
- if (perm_rootaccess("disabling the firewalling configuration")){
- IPFW_RULES_FORWARD frules;
- IPFW_RULES_INPUT brules;
- IPFW_RULES_OUTPUT orules;
- f_current_forwd.unlink();
- f_current_block.unlink();
- f_current_output.unlink();
- if (ipfw_open() != -1
- && frules.disable(1,NULL) != -1
- && brules.disable(1,NULL) != -1
- && orules.disable(1,NULL) != -1){
- ipfw_close();
- ret = 0;
- }
- }
- return ret;
- }
- /*
- Edit the default configuration of the firewall
- */
- void firewall_editc()
- {
- IPFW_RULES_FORWARD frules;
- IPFW_RULES_INPUT brules;
- IPFW_RULES_OUTPUT orules;
- DIALOG dia;
- dia.newf_chk (MSG_U(F_BRULES,"Inputing rules"),brules.active,"are active");
- dia.newf_chk (MSG_U(F_FRULES,"forwarding rules"),frules.active,"are active");
- dia.newf_chk (MSG_U(F_ORULES,"outputing rules"),orules.active,"are active");
- if (dia.edit("Global control of the firewalling/accounting"
- ,"You are allowed to disable/enable all rule sets\n"
- "without deleting them. Beware that activating\n"
- "an empty rule set is closing all doors!!!"
- ,help_ipfw.getpath()
- ,0)==MENU_ACCEPT){
- brules.save();
- frules.save();
- orules.save();
- }
-
- }
- /*
- Edit forwarding rules
- */
- void firewall_editf()
- {
- IPFW_RULES_FORWARD frules;
- frules.edit();
- }
- /*
- Edit blocking rules
- */
- void firewall_editb()
- {
- IPFW_RULES_INPUT brules;
- brules.edit();
- }
- /*
- Edit outputing rules
- */
- void firewall_edito()
- {
- IPFW_RULES_OUTPUT brules;
- brules.edit();
- }
-
- /*
- Edit accounting rules
- */
- void firewall_edita()
- {
- xconf_notice ("Sorry, not implemented yet!");
- // IPFW_RULES_ACCT arules;
- // arules.edit();
- }
-
-
-